
class RequestEvent < Event

  class Redirect < Exception
    attr_accessor :url
    def initialize url
      @url = url
    end
  end

  def initialize name = nil, data = nil
    if data == nil
      data = name || {}
      name = nil
    end
    strigified_keys = {}
    data = data.keys.each { |k|
      strigified_keys[k.to_s] = data[k]
    }
    super(name || 'request_event', strigified_keys)
    @link = {}
  end

  def fire
    begin
      super
    rescue Redirect => redirect
      set_response "", 303, 'Location' => redirect.url
    end
  end

  def set_response body, code = 200, headers = {}
    respond(:response => Rack::Response.new(body, code, headers))
    nil
  end

  def url
    domain + (env['PATH_INFO'] || '')
  end

  def domain
     url = scheme + "://" + host

     if scheme == "https" && port != 443 ||
         scheme == "http" && port != 80
       url << ":#{port}"
     end
     url
  end

  def scheme
    request.scheme
  end

  def host
    request.host
  end

  def port
    request.port
  end

  def redirect url
    if url[0,1] == '/'
      url = domain + url
    end
    raise Redirect.new(url)
  end

  def link page
    @link[page] ||= {}
    @link[page][controller] ||= controller.link(page, self)
  end

  def sublink page
    '/'+File.join(*(env[:tail] - env[:unprocessed_tail] + [page.to_s]))
    #controller.link(page, self)
  end

  def self.from_env env
    new('env' => env)
  end

  def params
    @data['params'] ||= request.params
  end

  def request
    @data['request'] ||= Rack::Request.new(@data['env'])
  end

  def session
    @data['session'] ||= data['env']["rack.session"]
  end





    class Mock < RequestEvent
      def initialize name = {}, params = nil
        if params == nil
          params = name
          name = nil
        end

        super({'env' => MOCK_ENV, 'params' => {}}.merge params)
      end
    end

    MOCK_ENV = {
      "jruby.rack.dynamic.requests.only"=>true,
      "rack.version"=>[1, 0],
      "rack.multithread"=>true,
      "rack.multiprocess"=>false,
      "rack.run_once"=>false,
      "rack.input"=> nil,
      "rack.errors"=> nil,
      "rack.url_scheme"=>"http",
      "java.servlet_request" => nil,
      "java.servlet_context" => nil,
      "jruby.rack.version"=>"0.9.5",
      "jruby.rack.jruby.version"=>"1.4.0",
      "jruby.rack.rack.release"=>"1.0",
      "REQUEST_METHOD"=>"GET",
      "SCRIPT_NAME"=>"",
      "REQUEST_URI"=>"/",
      "PATH_INFO"=>"/",
      "QUERY_STRING"=>"",
      "SERVER_NAME"=>"localhost",
      "REMOTE_HOST"=>"127.0.0.1",
      "REMOTE_ADDR"=>"127.0.0.1",
      "REMOTE_USER"=>"",
      "SERVER_PORT"=>"80",
      "HTTP_HOST"=>"localhost",
      "HTTP_CONNECTION"=>"keep-alive",
      "HTTP_USER_AGENT"=>"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.6 (KHTML, like Gecko) Chrome/4.0.266.0 Safari/532.6",
      "HTTP_CACHE_CONTROL"=>"max-age=0",
      "HTTP_ACCEPT"=>"application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
      "HTTP_ACCEPT_ENCODING"=> "gzip,deflate",
      "HTTP_COOKIE"=>"rack.session=BAh7AA%3D%3D%0A--211fd31bdc534613ebb3962793792a4976af6bde",
      "HTTP_ACCEPT_LANGUAGE"=>"cs-CZ,cs;q=0.8,ja;q=0.6",
      "HTTP_ACCEPT_CHARSET"=>"windows-1250,utf-8;q=0.7,*;q=0.3",
      "rack.request" => nil,
      "rack.request.cookie_string" => "rack.session=BAh7AA%3D%3D%0A--211fd31bdc534613ebb3962793792a4976af6bde",
      "rack.request.cookie_hash"=>{
        "rack.session" => "BAh7AA==\n--211fd31bdc534613ebb3962793792a4976af6bde"
      },
      "rack.session"=>{},
      "rack.session.options" => {
        :domain=>nil,
        :path=>"/",
        :expire_after=>2592000,
        :key=>"rack.session",
        :secret=>"antiperspirant pro zeny"}
      }


  class Test < FwTest

    def test_lazy_loading_request
      r = RequestEvent.from_env(MOCK_ENV)
      assert_equal r.data['request'], nil
      request = r.request
      assert_equal request.class, Rack::Request
      assert_equal r.data['request'], request
    end

    def test_params_shorthand
      r = RequestEvent.new(
        :params => { 'param' => 'value'}
      )
      assert_equal r.params['param'], 'value'
    end

    def test_session_shorthand
      r = RequestEvent.new(
        :session => { 'param' => 'value'}
      )
      assert_equal r.session['param'], 'value'
    end

    def test_redirect_raises_redirect_exception
      begin
        RequestEvent.new.redirect 'http://example.org'
        flunk 'Expected Redirect exception. None was thrown.'
      rescue Redirect => r
        eq r.url, 'http://example.org'
      end
    end

    def test_redirect_while_performing_action_gives_redirect_response
      test_event = Class.new(RequestEvent) do
        attr_accessor :listeners
      end
      event = test_event.new
      event.listeners = [lambda { |e| e.redirect 'my_url' }]
      event.fire
      eq event.response.length, 1
      eq event.response[0].data['response'].headers['Location'], 'my_url'
    end
  end
end